package common

import (
	"fmt"
	"io"
	"net/http"
	"time"
)

var (
	Version        = "Basic version (Need to use make to build the package)"
	Agent          = fmt.Sprintf("gitee-lfs-multipart-transfer %s", Version)
	BuildTime      string
	BuildCommit    string
	BuildGoVersion string
)

const (
	TRANSFER           = "transfer"
	TRANSFER_MULTIPART = "gitee-multipart"
	TRANSFER_BASIC     = "basic"

	OPT_UPLOAD = "upload"

	ERROR_CODE_INIT_FAILED   = 22
	ERROR_CODE_UPLOAD_FAILED = 23

	ENV_UPLOADER_LOG_ENABLE = "UPLOADER_LOG_ENABLE"

	HEADER_ALREADY_UPLOADED_SIZE = "X-Gitee-Already-Uploaded"
)

type EventType string

const (
	EventInit      EventType = "init"
	EventUpload    EventType = "upload"
	EventComplete  EventType = "complete"
	EventTerminate EventType = "terminate"
	EventProgress  EventType = "progress"
)

type Event struct {
	Event     EventType `json:"event,omitempty"`
	Operation string    `json:"operation,omitempty"`

	Remote              string `json:"remote,omitempty"`
	Concurrent          bool   `json:"concurrent,omitempty"`
	Concurrenttransfers int    `json:"concurrenttransfers,omitempty"`

	Oid      string `json:"oid,omitempty"`
	Size     int64  `json:"size,omitempty"`
	FilePath string `json:"path,omitempty"`

	// for process output
	BytesSoFar     int64 `json:"bytesSoFar,omitempty"`
	BytesSinceLast int64 `json:"bytesSinceLast,omitempty"`

	// for upload input
	Action *UploadParts `json:"action,omitempty"`

	Error *Error `json:"error,omitempty"`
}

type Link struct {
	Href      string            `json:"href"`
	Header    map[string]string `json:"header,omitempty"`
	ExpiresAt time.Time         `json:"expires_at,omitempty"`

	// only used for multipart upload
	PartOffset  int64        `json:"part_offset,omitempty"`
	PartSize    int64        `json:"part_size,omitempty"`
	PartNumber  int32        `json:"part_number,omitempty"`
	ChunkVerify *ChunkVerify `json:"chunk_verify,omitempty"`
}

type ChunkVerify struct {
	Href      string            `json:"href"`
	Header    map[string]string `json:"header,omitempty"`
	ExpiresAt time.Time         `json:"expires_at,omitempty"`
}

type UploadParts struct {
	Href   string            `json:"href,omitempty"`
	Header map[string]string `json:"header,omitempty"`
}

type Error struct {
	Code    int    `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

type LfsObject struct {
	Oid  string `json:"oid"`
	Size int64  `json:"size"`
}

type CompletedPart struct {
	PartNumber int32  `json:"part_Number"`
	ETag       string `json:"etag"`
}

type VerifyChunk struct {
	Object        *LfsObject     `json:"object"`
	CompletedPart *CompletedPart `json:"completed_part"`
}

func NewRequest(method, url string, body io.Reader, header map[string]string) (*http.Request, error) {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}

	for k, v := range header {
		req.Header.Set(k, v)
	}

	req.Header.Set("User-Agent", Agent)

	return req, nil
}
